package com.cloud.controller;

import com.cloud.entity.graph.ContributorVo;
import com.cloud.entity.graph.RankVo;
import com.cloud.entity.graph.RelationReturnVo;
import com.cloud.entity.graph.VertexVo;
import com.cloud.util.FileUtil;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.*;

@RestController
@RequestMapping("/api/graphx")
public class GraphxController {

    static String OS_PATH = FileUtil.isMac() ? "" : "/data/";

    static String webUrl = "http://localhost:8080";

    static {
        if (!FileUtil.isMac()) {
            webUrl = "http://172.29.7.160:8080";
        }
    }

    public static String[] orgNames = {
            "spring-projects", "google_research"
    };

    @GetMapping("/org")
    public String[] orgName() {
        return orgNames;
    }

    /**
     * 使用PageRank对组织里受欢迎度较高的人进行排序
     * 返回前 @total 的人, 默认是 10
     *
     * @param rankVo
     * @return
     */
    @PostMapping("/rank")
    public List<ContributorVo> rank(@RequestBody RankVo rankVo) throws Exception {
        String orgName = rankVo.getOrgName();
        Integer total = rankVo.getTotal();

        if (total == null) total = 10;
        if (orgName == null) throw new Exception("params{orgName} is null");
        checkOrgName(orgName);

        String rankPath = String.format(OS_PATH + "input_graph/%s/pageRank.txt", orgName);
        File rankFile = new File(rankPath);
        ArrayList<ContributorVo> ans = new ArrayList<>();
        try (FileReader fr = new FileReader(rankFile); BufferedReader br = new BufferedReader(fr)) {
            String line = br.readLine();
            for (int i = 0; i < total; i++) {
                ContributorVo vo = new ContributorVo();
                String[] data = line.split(",");
                vo.setUsername(data[0]);
                vo.setAvatarUrl(webUrl + "/images/" + vo.getUsername() + ".jpg");
                vo.setRank(Double.parseDouble(data[1]));
                ans.add(vo);
                line = br.readLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ans;
    }


    @PostMapping("/location")
    public Map<String, Integer> location(@RequestBody RankVo rankVo) throws Exception {
        String orgName = rankVo.getOrgName();
        if (orgName == null) throw new Exception("params{orgName} is null");
        checkOrgName(orgName);
        String locationPath = String.format(OS_PATH + "input_graph/%s/location.txt", orgName);
        Map<String, Integer> map = new HashMap<>();
        File locationFile = new File(locationPath);
        try (FileReader fr = new FileReader(locationFile);
             BufferedReader br = new BufferedReader(fr);
        ) {
            String line = br.readLine();
            while (line != null) {
                String[] data = line.split(":,");
                map.put(data[1], map.getOrDefault(data[1], 0) + 1);
                line = br.readLine();
            }
        }
        return map;
    }


    @PostMapping("/relation")
    public RelationReturnVo relation(@RequestBody RankVo rankVo) throws Exception {
        Integer total = rankVo.getTotal();
        String orgName = rankVo.getOrgName();
        if (total == null) total = 50;
        if (orgName == null) throw new Exception("params{orgName} is null");
        checkOrgName(orgName);
        String relationPath = String.format(OS_PATH + "input_graph/%s/relation.txt", orgName);
        RelationReturnVo returnVo = new RelationReturnVo();
        List<VertexVo> vertexVos = new ArrayList<>();
        HashMap<Integer, String> nodes = new HashMap<>();
        List<List<String>> edges = new ArrayList<>();
        int i = 0;
        try (FileReader fr = new FileReader(relationPath);
             BufferedReader br = new BufferedReader(fr)) {
            String line = br.readLine();
            while (line != null) {
                if (i == total) break;
                i++;
                String[] data = line.split(",");
                VertexVo vertexVo = new VertexVo();
                vertexVo.setNodeId(Integer.parseInt(data[0]));
                vertexVo.setUsername(data[1]);
                vertexVo.setInDegree(Integer.parseInt(data[2]));
                nodes.put(vertexVo.getNodeId(),
                        vertexVo.getUsername());
                vertexVos.add(vertexVo);
                line = br.readLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        String edgePath = String.format(OS_PATH + "input_graph/%s/edge.txt", orgName);
        try (FileReader fr = new FileReader(edgePath);
             BufferedReader br = new BufferedReader(fr)) {
            String line = br.readLine();
            while (line != null) {
                String[] data = line.split(" ");
                int srcId = Integer.parseInt(data[0]);
                int destId = Integer.parseInt(data[1]);
                if (nodes.containsKey(srcId) && nodes.containsKey(destId)) {
                    edges.add(new ArrayList<String>() {{
                        add(nodes.get(srcId));
                        add(nodes.get(destId));
                    }});
                }
                line = br.readLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        returnVo.setNode(vertexVos);
        returnVo.setEdge(edges);
        return returnVo;
    }

    public void checkOrgName(String orgName) throws Exception {
        for (String name : orgNames) {
            if (orgName.equals(name)) return;
        }
        throw new Exception("params{orgName} is not support");
    }
}
